package com.bibrApp.difu.fragment.account_mvp;


import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.PopupWindow;
import android.widget.TextView;

import com.bibrApp.difu.BeemIntent;
import com.bibrApp.difu.DfApp;
import com.bibrApp.difu.R;
import com.bibrApp.difu.base.BaseFragment;
import com.bibrApp.difu.dialog.InputPinDialog;
import com.bibrApp.difu.proto2javabean.WalletAssetBean;
import com.bibrApp.difu.utils.BigdecimalUtils;
import com.bibrApp.difu.utils.ClsPublicUtils;
import com.bibrApp.difu.utils.DialogUtils;
import com.bibrApp.difu.utils.Protocol;
import com.bibrApp.difu.utils.ToastUtils;
import com.bibrApp.difu.utils.UCaculateUtils;
import com.bibrApp.difu.utils.UIUtils;
import com.bibrApp.difu.widget.HorizontalDividerItemDecoration;
import com.google.protobuf.InvalidProtocolBufferException;
import com.googlecode.protobuf.format.JsonFormat;
import com.satoshilabs.trezor.lib.protobuf.TrezorMessageBitcoin;
import com.satoshilabs.trezor.lib.protobuf.TrezorMessageCommon;
import com.satoshilabs.trezor.lib.protobuf.TrezorMessageEthereum;

import org.web3j.utils.Convert;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.OnClick;

public class AccountFragment extends BaseFragment<AccountPresenter> implements IAccountView {

    @BindView(R.id.recycler_view)
    RecyclerView recyclerView;
    @BindView(R.id.tv_b_name)
    TextView tv_b_name;
    @BindView(R.id.tv_rate)
    TextView tvRate;
    @BindView(R.id.tv_cny)
    TextView tvCny;
    @BindView(R.id.tv_coin_num)
    TextView tvCoinNum;
    private Context mContext;
    private Activity mActivity;

    private UsbManager usbManager;//usb管理器
    private UsbDevice mUsbDevice;//找到的usb设备
    private UsbInterface mUsbInterface;
    private UsbDeviceConnection mUsbDeviceConnection;
    private final static int RATE = 1_0000_0000;
    private AccountAdapter adapter;
    private DfApp dfApp;
    @Override
    protected int getLayoutResId() {
        return R.layout.fragment_account;
    }

    @Override
    protected void initPresenter() {
        presenter = new AccountPresenter(getContext(), this);
        presenter.init();
    }

    @Override
    public void error(String msg) {

    }

    @Override
    public void successOfGetAssets(WalletAssetBean walletAssetBean) {
        if (walletAssetBean != null) {
            if (Double.parseDouble(walletAssetBean.getBalance()) > 0) {
                if (coinType.equalsIgnoreCase("eth")) {
                    BigDecimal blance = Convert.fromWei(walletAssetBean.getBalance(), Convert.Unit.ETHER);
                    tvCoinNum.setText(BigdecimalUtils.getBigDecimalPointNum(blance, 8) + "");
                    tvCny.setText(BigdecimalUtils.getBigDecimalPointNum(blance.multiply(BigDecimal.valueOf(rateD)), 4) + "CNY");
                } else {
                    String blance = BigdecimalUtils.format2Str(Double.parseDouble(walletAssetBean.getBalance()) / RATE, 8);
                    tvCoinNum.setText(blance);
                    DfApp dfApp = (DfApp) mActivity.getApplication();
                    dfApp.setBlance(blance);
                    tvCny.setText(BigdecimalUtils.format2Str(Double.parseDouble(walletAssetBean.getBalance()) / RATE * rateD, 4) + "CNY");
                }
            } else {
                tvCoinNum.setText("0.00");
                tvCny.setText("CNY 0.00");
            }
        }
        if (walletAssetBean != null && walletAssetBean.getTransactions() != null && walletAssetBean.getTransactions().size() > 0) {
            adapter.setNewData(walletAssetBean.getTransactions());
            adapter.setCoinType(coinType);
        }
    }

    double rateD;

    @Override
    public void successOfRate(String rate) {
        rateD = Double.parseDouble(rate);
        tvRate.setText(rate + " CNY/" + coinType);
    }

    @Override
    public void initView() {
        mContext = getContext();
        mActivity = getActivity();
        assert mContext != null;
        dfApp = (DfApp) Objects.requireNonNull(mActivity).getApplication();
        dfApp.setCoinType("BTC");
        usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(mContext)
                .color(getResources().getColor(R.color.black_f0))
                .margin(12)
                .build());
        adapter = new AccountAdapter();
        recyclerView.setAdapter(adapter);

//        adapter.addData(new AccountBean());
//        adapter.addData(new AccountBean());

        presenter.getRate(coinType.toLowerCase());
        getBtcData();

    }

    private void getBtcData() {
        checkUsb();
    }

    private void checkUsb() {
        if (usbManager == null) {
            return;
        }
        HashMap<String, UsbDevice> deviceHashMap = usbManager.getDeviceList();
        Iterator<UsbDevice> deviceIterator = deviceHashMap.values().iterator();
        ArrayList<String> usbDeviceList = new ArrayList<>();//存放usb数量
        while (deviceIterator.hasNext()) {
            UsbDevice device = deviceIterator.next();
            usbDeviceList.add(String.valueOf(device.getVendorId()));
            usbDeviceList.add(String.valueOf(device.getProductId()));
            if (device.getVendorId() == 0x1209 && device.getProductId() == 0x53C1) {//找到我们的usb设备
                mUsbDevice = device;
            }
        }
        //请求权限
        if (mUsbDevice == null) {
            ToastUtils.ShowToast(mContext, "没找到对应的usb设备");
            return;
        }
        if (usbManager.hasPermission(mUsbDevice)) {
            findIntfAndEpt();
        } else {
            getUsbPermission(mUsbDevice);
        }
    }

    /**
     * 寻找接口和分配结点
     */
    private UsbEndpoint usbEndpointIn;
    private UsbEndpoint usbEndpointOut;

    private void findIntfAndEpt() {
        if (mUsbDevice == null) {
            ToastUtils.ShowToast(mContext, "没有找到相匹配的设备");
            return;
        }
        if (mUsbDevice.getInterfaceCount() <= 0) {
            showToast("没有找到接口");
            return;
        }
        mUsbInterface = mUsbDevice.getInterface(0);
        //打开设备，获取UsbDeviceConnection对象，连接设备，用于后面的通讯
        UsbDeviceConnection usbDeviceConnection = usbManager.openDevice(mUsbDevice);
        if (usbDeviceConnection == null) {
            ToastUtils.ShowToast(mContext, "连接失败");
            return;
        }
        if (usbDeviceConnection.claimInterface(mUsbInterface, true)) {
            //找到接口
            mUsbDeviceConnection = usbDeviceConnection;
            //用于UsbDeviceConnection与UsbInterface进行端点设置和通讯
            if (mUsbInterface.getEndpoint(0) != null) {
                usbEndpointIn = mUsbInterface.getEndpoint(0);
            }
            if (mUsbInterface.getEndpoint(1) != null) {
                usbEndpointOut = mUsbInterface.getEndpoint(1);
            }
            initU();
        } else {
            //断开连接
            usbDeviceConnection.close();
        }
    }

    private void getETH() {
        //获取地址
        TrezorMessageEthereum.EthereumGetAddress.Builder ethGetAddressBuilder = TrezorMessageEthereum.EthereumGetAddress.newBuilder();
        List<Integer> address = new ArrayList<>(5);
        address.add(UCaculateUtils.changeNum(44));
        address.add(UCaculateUtils.changeNum(60));
        address.add(UCaculateUtils.changeNum(0));
        address.add(UCaculateUtils.changeNum(0, false));
        address.add(UCaculateUtils.changeNum(0, false));
        ethGetAddressBuilder.addAllAddressN(address);
        TrezorMessageEthereum.EthereumGetAddress getAddress = ethGetAddressBuilder.build();
        byte[] init = getAddress.toByteArray();//转成16进制

        if (mUsbDeviceConnection == null) {
            ToastUtils.ShowToast(mContext, "没有建立连接");
            return;
        }

        //添加协议 获取公钥 = 450  获取地址 56
        List<byte[]> bytes = Protocol.encode(56, getAddress.toByteArray());
        // 1,发送准备命令
        //通过usb hid传输数据给u盾
        for (int i = 0; i < bytes.size(); i++) {
            byte[] sendbytes = bytes.get(i);
            Log.d("dj", "==发送数据==" + ClsPublicUtils.bytesToHex(sendbytes));
            mUsbDeviceConnection.bulkTransfer(usbEndpointOut, sendbytes, sendbytes.length, 5000);
        }
        getHidMsg();
    }

    private void initU() {
        int ret = -100;

        TrezorMessageBitcoin.GetPublicKey.Builder publickey = TrezorMessageBitcoin.GetPublicKey.newBuilder();
        publickey.setCoinName("Bitcoin");//币种名
        publickey.setScriptType(TrezorMessageBitcoin.InputScriptType.SPENDADDRESS);//这里有几个选项，具体看要求，要问要求是啥，我也不知道
//        publickey.setShowDisplay(true);//是否显示在屏幕

        List<Integer> address = new ArrayList<>(3);
        address.add(UCaculateUtils.changeNum(44));
        address.add(UCaculateUtils.changeNum(0));
        address.add(UCaculateUtils.changeNum(0));
        publickey.addAllAddressN(address);
        TrezorMessageBitcoin.GetPublicKey getPublicKey = publickey.build();//组装成对应的protobuf文件中的方法
        Log.d("dj", "===publickeyjson===" + JsonFormat.printToString(getPublicKey));
        byte[] init = getPublicKey.toByteArray();//转成16进制

        if (mUsbDeviceConnection == null) {
            ToastUtils.ShowToast(mContext, "没有建立连接");
            return;
        }

        //添加协议 getpublickey = 11
        List<byte[]> bytes = Protocol.encode(11, init);
        // 1,发送准备命令
        //通过usb hid传输数据给u盾
        for (int i = 0; i < bytes.size(); i++) {
            byte[] sendbytes = bytes.get(i);
            Log.d("dj", "==发送数据==" + ClsPublicUtils.bytesToHex(sendbytes));
            mUsbDeviceConnection.bulkTransfer(usbEndpointOut, sendbytes, sendbytes.length, 5000);
        }
        getHidMsg();
    }

    /**
     * 获取u盾的消息
     */
    @SuppressLint("StaticFieldLeak")
    public void getHidMsg() {
        new AsyncTask<String, Integer, List<byte[]>>() {
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                //开始接受信息
                DialogUtils.showDialog(mContext);
            }

            @Override
            protected List<byte[]> doInBackground(String... params) {
                List<byte[]> byteRe = new ArrayList<>();
                try {
                    boolean isContinue = true;
                    while (isContinue) {
                        byte[] recByte = new byte[64];
                        mUsbDeviceConnection.bulkTransfer(usbEndpointIn, recByte, recByte.length, 10000);
                        if (Protocol.hasHead(recByte)) {
                            byteRe.add(recByte);
                        } else {
                            isContinue = false;
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return byteRe;
            }

            @SuppressLint("NewApi")
            @Override
            protected void onPostExecute(List<byte[]> bytes) {
                if (bytes == null || bytes.size() == 0) {
                    //接受信息失败
                    DialogUtils.dismissDialog();
                    return;
                }
                DialogUtils.dismissDialog();
                Log.d("dj", "==解码=前=" + ClsPublicUtils.bytesToHex(bytes.get(0)));
                Log.d("dj", "==解码=后=" + Protocol.decode(bytes));
                try {
                    if (Protocol.getType(bytes) == 3) {//失败
                        TrezorMessageCommon.Failure failure = TrezorMessageCommon.Failure.parseFrom(ClsPublicUtils.hexToBytes(Protocol.decode(bytes)));
                        ToastUtils.ShowToast(mContext, failure.getMessage());
                    } else if (Protocol.getType(bytes) == 18) {//需要输入pin码
                        showPinDialog();
                    } else if (Protocol.getType(bytes) == 12) {
                        TrezorMessageBitcoin.PublicKey publicKey = TrezorMessageBitcoin.PublicKey.parseFrom(ClsPublicUtils.hexToBytes(Protocol.decode(bytes)));
                        String publicKeyJson = JsonFormat.printToString(publicKey);
//                        JSONObject jsonObject= JSONObject.parseObject(publicKeyJson);
                        DfApp dfApp = (DfApp) mActivity.getApplication();
                        dfApp.setXpub(publicKey.getXpub());
                        presenter.getBtcBlance(coinType.toLowerCase(), publicKey.getXpub());
                        Log.d("dj", "==public=key=json=" + publicKey);
//                        Log.d("dj","==public=2=json="+jsonObject.toString());
                    } else if (Protocol.getType(bytes) == 451) {//EthereumPublicKey = 451
                        TrezorMessageEthereum.EthereumPublicKey publicKey = TrezorMessageEthereum.EthereumPublicKey.parseFrom(ClsPublicUtils.hexToBytes(Protocol.decode(bytes)));
                        Log.d("dj", "==public=key=eth=" + publicKey);
                        presenter.getEthBlance(coinType.toLowerCase(), publicKey.getXpub());
                    } else if (Protocol.getType(bytes) == 57) {//EthereumAddress = 57
                        TrezorMessageEthereum.EthereumAddress address = TrezorMessageEthereum.EthereumAddress.parseFrom(ClsPublicUtils.hexToBytes(Protocol.decode(bytes)));
                        Log.d("dj", "==public=key=eth=" + address);
                        presenter.getEthBlance(coinType.toLowerCase(), address.getAddress());
                    }

                } catch (InvalidProtocolBufferException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        }.execute();
    }

    /**
     * 弹出输入pin码的弹窗
     */
    private InputPinDialog.Builder mDialog;

    private void showPinDialog() {
        if (mDialog == null) {
            mDialog = new InputPinDialog.Builder(mContext, R.style.OrderDialogStyle);
        }
        mDialog.setOnSureBtnClick(new InputPinDialog.OnSureBtnClick() {
            @Override
            public void onClickSure(String numTV) {
                sendPin(numTV);
                mDialog.dismiss();
            }
        });
        Log.d("dj", "请输入pin码");
        mDialog.creater().show();
    }

    /**
     * 发送pin给u盾
     */
    private void sendPin(String numTV) {
        TrezorMessageCommon.PinMatrixAck.Builder pinMatrixAckBuilder = TrezorMessageCommon.PinMatrixAck.newBuilder();
        pinMatrixAckBuilder.setPin(numTV);
        TrezorMessageCommon.PinMatrixAck pinMatrixAck = pinMatrixAckBuilder.build();//组装成对应的protobuf文件中的方法
        byte[] init = pinMatrixAck.toByteArray();//转成16进制

        if (mUsbDeviceConnection == null) {
            ToastUtils.ShowToast(mContext, "没有建立连接");
            return;
        }

        //添加协议 19 发送pin码
        List<byte[]> bytes = Protocol.encode(19, pinMatrixAck.toByteArray());
        // 1,发送准备命令
        //通过usb hid传输数据给u盾
        for (int i = 0; i < bytes.size(); i++) {
            byte[] sendbytes = bytes.get(i);
            mUsbDeviceConnection.bulkTransfer(usbEndpointOut, sendbytes, sendbytes.length, 5000);
        }
        getHidMsg();
    }

    private Receiver mUsbReceiver;

    //开始申请USB权限
    private void getUsbPermission(UsbDevice mUSBDevice) {
        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(BeemIntent.ACTION_USB_INTENT), 0);
        IntentFilter filter = new IntentFilter(BeemIntent.ACTION_USB_INTENT);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
        mUsbReceiver = new Receiver();
        mContext.registerReceiver(mUsbReceiver, filter);
        usbManager.requestPermission(mUSBDevice, pendingIntent); // 该代码执行后，系统弹出一个对话框/等待权限
    }

    private class Receiver extends BroadcastReceiver {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (BeemIntent.ACTION_USB_INTENT.equals(action)) {
                synchronized (this) {
                    UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)
                            && mUsbDevice.equals(device)) {
                        //TODO 授权成功，操作USB设备
                        ToastUtils.ShowToast(mContext, "usb授权成功");
//                        findIntfAndEpt();
                    } else {
                        //用户点击拒绝了
                        ToastUtils.ShowToast(mContext, "拒绝usb授权");
                    }
                }
            }
        }
    }

    private PopupWindow popupWindow;
    private String coinType = "BTC";

    @OnClick(R.id.tv_b_name)
    public void bNameClick() {
        View layout = View.inflate(mContext, R.layout.pop_coin_type, null);
        layout.findViewById(R.id.tv_all).setVisibility(View.GONE);
        layout.findViewById(R.id.tv_btc).setOnClickListener(view -> {
            tv_b_name.setText("BTC");
            coinType = "BTC";
            dfApp.setCoinType(coinType);
            getBtcData();
            presenter.getRate(coinType);
            popupWindow.dismiss();
            sendCoinTypeBroadCast();
        });
        layout.findViewById(R.id.tv_eth).setOnClickListener(view -> {
            tv_b_name.setText("ETH");
            coinType = "ETH";
            dfApp.setCoinType(coinType);
//            adapter.setNewData(new ArrayList<>());
//            presenter.getDatas(pageNum, coinType, type);
            presenter.getRate(coinType.toLowerCase());
            getETH();
            popupWindow.dismiss();
            sendCoinTypeBroadCast();
        });
        layout.findViewById(R.id.tv_usdt).setOnClickListener(view -> {
            tv_b_name.setText("USDT");
            coinType = "USDT";
//            adapter.setNewData(new ArrayList<>());
//            presenter.getDatas(pageNum, coinType, type);
            popupWindow.dismiss();
        });

        popupWindow = new PopupWindow(layout, UIUtils.dpToPixels(mContext, 68), -2, true);
        popupWindow.setFocusable(true);

        popupWindow.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#00000000")));
        popupWindow.setOutsideTouchable(true);
        popupWindow.showAsDropDown(tv_b_name, 0, 0);
    }

    /**
     * 更新币种广播
     */
    private void sendCoinTypeBroadCast() {
        Intent intent = new Intent();
        intent.setAction(BeemIntent.ACTION_UPDATE_CION_TYPE_INTENT);
        intent.putExtra("coinType",coinType);
        mContext.sendBroadcast(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mUsbReceiver != null) {
            mContext.unregisterReceiver(mUsbReceiver);
        }
    }
}
